/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 */

#include <string.h>
#include <tcp_transparent.h>

#if !defined(SAL_USING_POSIX)
#error "Please enable SAL_USING_POSIX!"
#else
#include <sys/time.h>
#include <sys/select.h>
#endif
#include <sys/socket.h> /* 使用BSD socket，需要包含socket.h头文件 */
#include "netdb.h"
#include <arpa/inet.h>         /* 包含 ip_addr_t 等地址相关的头文件 */
#include <netdev.h>            /* 包含全部的 netdev 相关操作接口函数 */
#include "setting.h"

#define DEBUG_TCP_CLIENT

#define DBG_TAG               "TCP"
#ifdef DEBUG_TCP_CLIENT
#define DBG_LVL               DBG_LOG
#else
#define DBG_LVL               DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>

#define BUFSZ   1024

static int started = 0;
static int is_running = 0;
static char url[256];
static int port = 8080;

static int sock_tcp = -1;
//发送方法
static func_ptr_arg2_ret_t to_send;

extern device_param_t device_setting;

static void tcpclient(void *arg)
{
    char *recv_data;
    int bytes_received;

    struct hostent *host = RT_NULL;
    struct sockaddr_in server_addr;

    struct timeval timeout;
    fd_set readset;
__start:
    //判断网卡状态
    if(netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP) == NULL)
    {
        LOG_E("Netdev get first by linkup failed!");
        goto __exit;
    }
    /* 通过函数入口参数url获得host地址（如果是域名，会做域名解析） */
    host = gethostbyname(url);
    if (host == RT_NULL)
    {
        LOG_E("Get host by name failed!");
        goto __exit;
    }
    /* 分配用于存放接收数据的缓冲 */
    recv_data = rt_malloc(BUFSZ);
    if (recv_data == RT_NULL)
    {
        LOG_E("No memory");
        return;
    }

    /* 创建一个socket，类型是SOCKET_STREAM，TCP类型 */
    if ((sock_tcp = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        /* 创建socket失败 */
        LOG_E("Create socket error");
        goto __exit;
    }

    /* 初始化预连接的服务端地址 */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

    /* 连接到服务端 */
    if (connect(sock_tcp, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
    {
        /* 连接失败 */
        LOG_E("Connect fail!");
        goto __exit;
    }

    started = 1;
    is_running = 1;

    timeout.tv_sec = 3;
    timeout.tv_usec = 0;

    while (is_running)
    {
        FD_ZERO(&readset);
        FD_SET(sock_tcp, &readset);

        /* Wait for read */
        if (select(sock_tcp + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
            continue;

        /* 从sock连接中接收最大BUFSZ - 1字节数据 */
        bytes_received = recv(sock_tcp, recv_data, BUFSZ - 1, 0);
        if (bytes_received < 0)
        {
            /* 接收失败，关闭这个连接 */
            LOG_E("Received error, close the socket.");
            goto __exit;
        }
        else if (bytes_received == 0)
        {
            /* 打印recv函数返回值为0的警告信息 */
            LOG_W("Received warning, recv function return 0.");
            goto __exit;
            //continue;
        }
        else
        {
            //发送到
            to_send((rt_uint8_t *)recv_data, bytes_received);
        }
    }

__exit:
    if (recv_data)
    {
        rt_free(recv_data);
        recv_data = RT_NULL;
    }
    if (sock_tcp >= 0)
    {
        closesocket(sock_tcp);
        sock_tcp = -1;
    }
    started = 0;
    is_running = 0;
    rt_thread_mdelay(1000);
    goto __start;
    return;
}

void tcp_transparent_init(func_ptr_arg2_ret_t send)
{
    rt_thread_t tid = RT_NULL;

    //设置发送方法
    to_send = send;

    if(GET_BIT_OF(device_setting->fun_enable, 0))
    {
        rt_memset(url, 0x0, sizeof(url));
        rt_strncpy(url, device_setting->server_params.host, rt_strlen(device_setting->server_params.host));
        port = device_setting->server_params.port;

        tid = rt_thread_create("tcp_client",
            tcpclient, RT_NULL,
            2048, RT_THREAD_PRIORITY_MAX/3, 20);
    }
    else
    {
        rt_memset(url, 0x0, sizeof(url));
        rt_strncpy(url, device_setting->server_params.host, rt_strlen(device_setting->server_params.host));
        port = device_setting->server_params.port;

        tid = rt_thread_create("tcp_client",
            tcpclient, RT_NULL,
            2048, RT_THREAD_PRIORITY_MAX/3, 20);
    }

    if (tid != RT_NULL)
    {
        rt_thread_startup(tid);
    }
    return;
}


rt_uint8_t tcp_transparent_send(rt_uint8_t *data, rt_uint32_t length)
{
    int ret = -1, err = 1;
    if(sock_tcp >= 0)
    {
        ret = send(sock_tcp, data, length, 0);
        if (ret < 0)
        {
            is_running = 0;
            err = 0;
            /* 发送失败，关闭这个连接 */
            rt_kprintf("send error, close the socket.");
        }
        else if (ret == 0)
        {
            err = 0;
            /* 打印send函数返回值为0的警告信息 */
            rt_kprintf("Send warning, send function return 0.");
        }
    }
    else
    {
        err = 0;
    }

    return err;
}
